package com.zyj.core.sqlsource;

import com.zyj.core.parser.SqlSourceParser;
import com.zyj.core.sqlnode.DynamicContext;
import com.zyj.core.sqlnode.SqlNode;

/**
 * 用于封装和解析不带有 ${}或者动态标签的SQL信息
 * SELECT * FROM user WHERE id = #{id}
 * <p>
 * 被封装的SQL信息，只需要解析一次，就可以得到以下的SQL语句
 * SELECT * FROM user WHERE id = ?
 * <p>
 * * 解析时机：
 * * 1、RawSqlSource构造的时候进行SQL解析（只会解析一次）
 * * 2、DynamicSqlSource每次调用getBoundSql的时候才会解析
 */
public class RawSqlSource implements SqlSource {

    /**
     * RawSqlSource持有staticSqlSource
     */
    // sql解析之后的结果保存在staticSqlSource之中，后续根据staticSqlSource中解析好的sql，在调用getBoundSql方法时，封装成BoundSql对象
    private SqlSource staticSqlSource;

    /**
     * 传入的mixedSqlNode是已经根据配置文件中的标签解析完成，封装好的SqlNode对象
     *
     * @param rootSqlNode
     */
    public RawSqlSource(SqlNode rootSqlNode) {
        // 1.解析SqlNode中的所有节点信息，最终会组成一条SQL语句
        DynamicContext context = new DynamicContext(null);
        // 调用apply方法完成sql片段的拼接
        rootSqlNode.apply(context);
        // 2.解析#{}
        // 在此处已经完成了sql片段的拼接，剩下#{}没有被替换
        // sql为：SELECT * FROM user WHERE sex = #{sex}
        String sqlText = context.getSql();

        // 得到一个sql解析器
        SqlSourceParser sqlSourceParser = new SqlSourceParser();

        /**
         * 在RawSqlSource对象创建的时候，就已经完成了sql的解析工作，而对于DynamicSqlSource来说，解析sql的时机推迟到了调用getBoundSql方法的时候
         */
        // 调用sql解析器来完成sql的解析工作，解析#{}
        staticSqlSource = sqlSourceParser.parseSqlSource(sqlText);
    }

    @Override
    public BoundSql getBoundSql(Object param) {

        // 此处调的是StaticSqlSource中实现的getBoundSql方法，而不再是RawSqlSource中的了
        return staticSqlSource.getBoundSql(param);
    }
}
